#pragma once 

#include <vector>
#include <string>
#include <map>
#include <assert.h>
#include <math.h>

#include "TagList.h"


namespace LightPlayer {

	typedef					char				si8;
	typedef					short				si16;
	typedef					int					si32;
	typedef			   long long				si64;
	typedef unsigned		char				ui8;
	typedef unsigned		short				ui16;
	typedef unsigned		int					ui32;
	typedef unsigned   long long				ui64;


	typedef	si8		int8;
	typedef	si16	int16;
	typedef	si32	int32;
	typedef si64	int64;
	typedef ui8		uint8;
	typedef ui16	uint16;
	typedef ui32	uint32;
	typedef ui32	uint;
	typedef ui64	uint64;

	typedef std::string string;
	using namespace std;

	template <typename T>
	class array : public std::vector<T>{
	};

	template <typename key, typename value>
	class dictionary : public std::map<key,value>{
	};

	template <typename T1, typename T2>
	class link : public std::pair<T1,T2>{
	public:
		link(const T1& _Val1, const T2& _Val2)
		: std::pair<T1,T2>(_Val1, _Val2)
		{}
	};

	// TWIPS conversion
	#define TWIPS_SIZE (1.0f/20.0f)

	#define PIXELS_TO_TWIPS(X) (X/TWIPS_SIZE)
	#define TWIPS_TO_PIXELS(X) (X*TWIPS_SIZE)

#ifndef M_PI
	#define M_PI       3.14159265358979323846f
#endif

	#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0f / M_PI))
	#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0f * M_PI)


	// struct 
	class Stream;

	//////////////////////////////////////////////////////////////////////////
	// Vector 2d
	//////////////////////////////////////////////////////////////////////////

	struct vec2{
		float x,y;
		vec2( float _x=0, float _y=0){
			set(_x,_y);
		}
		void set( float _x=0, float _y=0){
			x=_x;y=_y;
		}
		float GetX() const { return x; };
		float GetY() const { return y; };

		bool equalByEpsilon(const vec2& other, const float ep = 0.0001f )const{
			return ( (x >= other.x-ep) && (x <= other.x+ep) ) 
				&& ( (y >= other.y-ep) && (y <= other.y+ep) );
		}

		bool operator==(const vec2& other)const{
			return (x==other.x && y==other.y); 
		}
		vec2 operator+(const vec2& other)const{
			return vec2(x+other.x,y+other.y); 
		}
		vec2 operator-(const vec2& other)const{
			return vec2(x-other.x,y-other.y); 
		}
		vec2 operator*(float K)const{
			return vec2(x*K,y*K); 
		}
		vec2 operator/(float K)const{
			return vec2(x/K,y/K); 
		}
		float dot(const vec2& other)const{
			return (x*other.x + y*other.y); 
		}
		vec2 perpendicular()const{
			return vec2(y,-x); 
		}
		bool isLeft(const vec2& other)const{
			return (x*other.y - y*other.x) < 0;
		}
		float length()const{
			return sqrt(x*x + y*y); 
		}
	};

	//////////////////////////////////////////////////////////////////////////
	// Matrix
	//////////////////////////////////////////////////////////////////////////

	struct MATRIX{
		float _11, _12, _13, 
			_21, _22, _23;
				MATRIX();
		void	setIdentity();
		void	setScaleMatrix(float scale_x, float scale_y);
		void	setRotationMatrix(float angle);
		void	readFromStream(Stream* stream);
		vec2	operator*(const vec2& vec) const;
		MATRIX	operator*(const MATRIX& mat) const;
		vec2	convertToMatrixCoord(const vec2& vec) const;
		void	multBy(float k);
		void	invertByMinor();
		void	transpose();
		float	determinant() const;
		void	invert();


		vec2	getColumn0() const;
		vec2	getColumn1() const;
		vec2	getColumn2() const;
		void	setColumn0(const vec2& AxisX);
		void	setColumn1(const vec2& AxisY);
		void	setColumn2(const vec2& Translation);

		void	setX(float X);
		void	setY(float Y);
		float	getX() const;
		float	getY() const;

		void	setScaleX(float X);
		void	setScaleY(float Y);
		float	getScaleX() const;
		float	getScaleY() const;

		void	setRotation(float angle);
		float	getRotation() const;
	};

	//////////////////////////////////////////////////////////////////////////
	// RECT
	//////////////////////////////////////////////////////////////////////////

	struct OBB;

	struct RECT{
		float Xmin, Xmax, Ymin, Ymax;
		RECT(float _xmin = 0, float _xmax = 0, float _ymin = 0, float _ymax = 0);
		void readFromStream(Stream* stream);
		float width() const { return(Xmax-Xmin); };
		float height() const { return(Ymax-Ymin); };
		void init(float _xmin = 0, float _xmax = 0, float _ymin = 0, float _ymax = 0);
		void extend(const RECT& other);
		void transform(const MATRIX& transformation);
		bool isNull() const { return (Xmin == 0 && Xmax == 0 && Ymin == 0 && Ymax == 0); }

		void operator= (const RECT& o);
		void operator= (const OBB& o);
	};

	/*    D---------C   */
	/*    |         |   */
	/*    |   OBB   |   */
	/*    |         |   */
	/*    A---------B   */
	struct OBB{
		vec2 A,B,C,D;
		OBB();
		void init();
		float width() const;
		float height() const;
		void transform(const MATRIX& transformation);
		float GetMinX() const;
		float GetMinY() const;
		float GetMaxX() const;
		float GetMaxY() const;
		void operator= (const OBB& o);
		void operator= (const RECT& o);
	};


	//////////////////////////////////////////////////////////////////////////
	// TAG
	//////////////////////////////////////////////////////////////////////////

	struct TAG{
		TagList type;
		uint32 size;

		void SetTagType(uint32 _type) { SetTagType( (TagList)_type ); };
		void SetTagType(TagList _type) {type = _type; };
		TAG(uint32 _type = 0, uint32 _size = 0);
		void readFromStream(Stream* stream);
	};

	//////////////////////////////////////////////////////////////////////////
	// RGB / RGBA
	//////////////////////////////////////////////////////////////////////////

	struct RGB{
		uint8 R,G,B;
		void readFromStream(Stream* stream);
	};

	struct RGBA{
		uint8 R,G,B,A;
		RGBA(uint8 _R = 0, uint8 _G = 0, uint8 _B = 0, uint8 _A = 0);
		void readFromStream(Stream* stream);
		void readARGBFromStream(Stream* stream);
		void readRGBFromStream(Stream* stream);
		float R01(){ return (R/255.0f); }
		float G01(){ return (G/255.0f); }
		float B01(){ return (B/255.0f); }
		float A01(){ return (A/255.0f); }
	};

	//////////////////////////////////////////////////////////////////////////
	// CXFORM
	//////////////////////////////////////////////////////////////////////////

	struct CXFORM{
		float _MultR, _MultG, _MultB, _MultA, 
			  _AddR,  _AddG,  _AddB,  _AddA;
		CXFORM(float mr=1.0f, float mg=1.0f, float mb=1.0f, float ma=1.0f,
				float ar=0.0f, float ag=0.0f, float ab=0.0f, float aa=0.0f);
		void init(float mr=1.0f, float mg=1.0f, float mb=1.0f, float ma=1.0f,
				float ar=0.0f, float ag=0.0f, float ab=0.0f, float aa=0.0f);
		void readRGBFromStream(Stream* stream);
		void readRGBAFromStream( Stream* stream );

		CXFORM operator*(const CXFORM& other) const;
		const CXFORM& operator*=(const CXFORM& other);
	};




	typedef link<const char*,uint16> type_label_list;
	typedef array<type_label_list> FrameLabelList;

#define string_readFromString(__constCharStar,__streamPointer) \
	__constCharStar = ((const char*)(__streamPointer)->getCurrentPosition());\
	(__streamPointer)->skip_byte( strlen(__constCharStar) + 1 );\


	static const char s_empty_string[] = "";
};